cmake_minimum_required(VERSION 3.17)
project(HelloCMake)

# 输出一个信息
message(STATUS "----------    Hello, CMAKE    ----------")

# 设置一个变量
set(PLAYER "Jackeylove")
set(PLAYER_VAR "PLAYER")

# 输出变量，如果不使用${}语法，则输出会变量字符串（TIP：CMAKE中的任何Token都视为一个字符串）
message(STATUS ${PLAYER})
# 这里就是CMAKE的有意思的地方了，先通过PLAYER_VAR取到一个PLAYER的字符串，然后再用这个PLAYER的名称获得Jackeylove。这就是CMAKE的嵌套逻辑
message(STATUS "${PLAYER_VAR} = ${${PLAYER_VAR}}")
# 输出一个外部的参数：
# 我第一次输入了10，而第二次没有输入。结果这个10还保留着。这就是缓存在了吗？
message(STATUS "MY_VAR = ${MY_VAR}")
# 系统内变量
message(STATUS "PROJECT_NAME = ${PROJECT_NAME}")

# 数学运算
set(MY_NUMBER 5)
math(EXPR RESULT_VAR "10 * ${MY_NUMBER}")
message(STATUS "RESULT_VAR = ${RESULT_VAR}")

# 设置一个列表
set(MY_LIST 1 2 3)
# 增加一个项目
list(APPEND MY_LIST 10)
# 输出列表，注意这里不会格式化，有些版本看似输出的是123一个数字，其实他是三个，只是他不会加空格（但我这个版本加上了“;”做为分隔，改进了）
message(STATUS "MYLIST = ${MY_LIST}")
# 得到列表的长度=>MY_LIST_LEN
list(LENGTH MY_LIST MY_LIST_LEN)
message(STATUS "MY_LIST_LEN = ${MY_LIST_LEN}")
# 得到列表中的一个项目
list(GET MY_LIST 0 MY_LIST_ITEM)
message(STATUS "MY_LIST_ITEM = ${MY_LIST_ITEM}")
# CMake中的类型：String, Number, List, Path, Boolean

# 设置一个BOOL值
set(MY_BOOLEAN NO) # 可以用以下值代表（非常灵活）：TRUE,FALSE,ON,OFF,YES,NO,Y,N,1,0,IGNORE,NOTFOUND
# 判断
if (MY_BOOLEAN) # 注意这里可以不使用${}来提取变量，if的表达式里面会自动计算，当然加上也没问题
    message(STATUS "MY_BOOLEAN is true.")
elseif(TRUE)
    message(STATUS "MY_BOOLEAN is false. and elseif true.")
else()
    message(STATUS "MY_BOOLEAN is false.")
endif()
# 对比字符串，比较使用EQUAL,GREATER这类，而不是使用=,>，列表使用IN_LIST，这些以后问AI吧。
SET(MY_STR "Strings")
if (MY_STR STREQUAL "Strings")
    message(STATUS "MY_STR is equal.")
endif()

# While循环
set(LOOP_INDEX 0)
while (LOOP_INDEX LESS 3)
    message(STATUS "Current Index: ${LOOP_INDEX}")
    math(EXPR LOOP_INDEX "${LOOP_INDEX} + 1")
endwhile()
# 遍历一个LIST
set(LOOP_INDEX 0)
while (LOOP_INDEX LESS MY_LIST_LEN)
    list(GET MY_LIST ${LOOP_INDEX} MY_LIST_ITEM)
    message(STATUS "Current Item: ${MY_LIST_ITEM}")
    math(EXPR LOOP_INDEX "${LOOP_INDEX} + 1")
endwhile()
# foreach 进行遍历
foreach (ELEMENT IN LISTS MY_LIST)
    message(STATUS "Foreach Item: ${ELEMENT}")
endforeach()

# 创建函数
function(my_function argument)
    message(STATUS "my_function | The argument is: ${argument}")
endfunction()
# 调用函数
my_function("Hello!")
# 使用无限参数的函数，从ARGV这个变量中获得
function(my_arg_fun)
    foreach (argument IN LISTS ARGV)
        message(STATUS "my_arg_fun | The argument is: ${argument}")
    endforeach()
endfunction()
# 调用函数
my_arg_fun("Hello" 1 2)
# 在函数内部设置值（模拟一个SET）
function(set_copy VAR_NAME VAR_VALUE)
    # 注意函数有域的概念，在函数体内部设置的变量，在退出函数体之后就消失了，
    # 如果想改变外面的设置，需要加上这个PARENT_SCOPE
    set(${VAR_NAME} ${VAR_VALUE} PARENT_SCOPE)    
endfunction()
# 调用函数
set_copy(MY_COPY_VAR 100)
message(STATUS "MY_COPY_VAR = ${MY_COPY_VAR}")

# 使用宏（macro）。macro和函数不一样的地方是，macro没有域的概念（即等于展开语句）
macro(set_copy_m VAR_NAME VAR_VALUE)
    set(${VAR_NAME} ${VAR_VALUE})    
endmacro()
# 调用宏
set_copy_m(MY_COPY_VAR 200)
message(STATUS "MY_COPY_VAR = ${MY_COPY_VAR}")
# 使用include
include(subfolder/Functions.cmake)
# 调用函数
log(TEXT "Hello Normal")
# 这行会打印一个警告，是有效的。
#log(TEXT "Hello Warning" WARNING)